﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;

namespace PathNodeGraphicEditor
{
    delegate void clicked();
    public partial class PNodeEdit : Form
    {
        const int rowCount = 10;
        const int colCount = 18;
        Button[] buttons;
        PathfindingInfo PFInfo;

        private Button buttonSelected;

        char[] delimiters = { ' ', 't', 'o' };
        //deletes waypoints and any connections that are using that node.
        private void DeleteWaypoint_Click(object sender, EventArgs e)
        {

            if (buttonSelected != null)
            {
                var n = PFInfo.nodeInfo.NodeList.Select<Node, Node>(Node => Node).Where(node => node.id == buttonSelected.TabIndex).FirstOrDefault();
                if (n != null)
                {
                    PFInfo.nodeInfo.NodeList.Remove(n);
                    buttonSelected.BackColor = Color.Transparent;
                }
                EdgeEndDrop.Items.Remove(buttonSelected.Name);
                EdgeBeginDrop.Items.Remove(buttonSelected.Name);
            }

            var edges = PFInfo.nodeInfo.EdgeList
                .Select<Edge, Edge>(Edge => Edge)
                .Where(edge => edge.startID == buttonSelected.TabIndex || edge.endID == buttonSelected.TabIndex).ToList();

            foreach (Edge edge in edges)
            {
                if(EdgeBox.Items.Contains(edge.startID + " to" + edge.endID))
                    EdgeBox.Items.Remove(edge.startID + " to" + edge.endID);

                PFInfo.nodeInfo.EdgeList.Remove(edge);
            }
            foreach (Button button in buttons)
            {
                button.Invalidate();
            }
        }

        public PNodeEdit()
        {
            InitializeComponent();
        }

        //adds a waypoint
        private void AddWaypoint_Click(object sender, EventArgs e)
        {
            if (buttonSelected != null)
            {
                string tempNode = buttonSelected.ToString();
                PFInfo.nodeInfo.NodeList.Add(new Node((uint)buttonSelected.TabIndex, (uint)(buttonSelected.Location.X + 25), (uint)(buttonSelected.Location.Y + 25)));
                buttonSelected.BackColor = Color.FromArgb(90, 255, 50, 50);
                if(!EdgeEndDrop.Items.Contains(buttonSelected.Name))
                    EdgeEndDrop.Items.Add(buttonSelected.Name);
                if (!EdgeBeginDrop.Items.Contains(buttonSelected.Name))
                    EdgeBeginDrop.Items.Add(buttonSelected.Name);
            }
        }

        //Contains a loop that creates the buttons based on the row and column count
        private void CreateNodes()
        {
            PFInfo = new PathfindingInfo();
            PFInfo.map.height = 512;
            PFInfo.map.width = 512;
            for (int i = 0; i < rowCount; i++)
            {
                for (int j = 0; j < colCount; j++)
                {
                    int x = j * 50;
                    int y = i * 50;

                    uint height = 50;
                    uint width = 50;

                    uint halfHeight = height / 2;
                    uint halfWidth = width / 2;
                    int index = i * colCount + j;

                    buttons[index] = new Button();
                    buttons[index].BackColor = System.Drawing.Color.Transparent;
                    buttons[index].BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
                    buttons[index].FlatStyle = System.Windows.Forms.FlatStyle.Flat;
                    buttons[index].Location = new System.Drawing.Point(x, y);
                    buttons[index].Name = index.ToString();
                    buttons[index].Size = new System.Drawing.Size((int)height, (int)width);
                    buttons[index].TabIndex = index;
                    buttons[index].Text = index.ToString();
                    buttons[index].UseVisualStyleBackColor = true;
                    buttons[index].Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                    buttons[index].Click += new System.EventHandler(this.ButtonClick);
                    this.Controls.Add(buttons[index]);
                    buttons[index].Parent = pictureBox1;
                }
            }
        }

        //Contains the code that is executed when a button is clicked, such as changing the color
        private void ButtonClick(object sender, EventArgs e)
        {
            Button senderButton = (Button)sender;
            Button previousButton = buttonSelected;
            buttonSelected = senderButton;
            if (previousButton != null)
            {
                if (previousButton.BackColor == Color.FromArgb(90, 255, 50, 50))
                    previousButton.BackColor = Color.FromArgb(90, 255, 50, 255);
                else
                    previousButton.BackColor = Color.Transparent;
            }
            if (senderButton.BackColor == Color.FromArgb(90, 255, 50, 255))
                senderButton.BackColor = Color.FromArgb(90, 255, 50, 50);
            else
                senderButton.BackColor = Color.FromArgb(90, 50, 255, 255);

        }
        
        //Calls initial calls to functions
        private void PNodeEdit_Load(object sender, EventArgs e)
        {
            buttons = new Button[rowCount * colCount];
            CreateNodes();
        }

        //creates edges if two nodes are selected in Edge Begin and Edge End
        private void CreateEdge_Click(object sender, EventArgs e)
        {
            if (EdgeBeginDrop.SelectedItem != null && EdgeEndDrop.SelectedItem != null && EdgeBeginDrop.SelectedItem != EdgeEndDrop.SelectedItem)
            {
                PFInfo.nodeInfo.EdgeList.Add(new Edge(Convert.ToUInt32(EdgeBeginDrop.SelectedItem), Convert.ToUInt32(EdgeEndDrop.SelectedItem), 1));
                EdgeBox.Items.Add(Convert.ToString(EdgeBeginDrop.SelectedItem) + " to" + Convert.ToString(EdgeEndDrop.SelectedItem));
                foreach (Button i in buttons)
                {
                    i.Invalidate();
                }
            }
        }

        //paint fucntion for edges
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            Pen use = new Pen(Color.Red, 2);
            foreach (Edge Edge in PFInfo.nodeInfo.EdgeList)
            {
                e.Graphics.DrawLine(use, new Point(buttons[Edge.startID].Location.X + 25, buttons[Edge.startID].Location.Y + 25), new Point(buttons[Edge.endID].Location.X + 25, buttons[Edge.endID].Location.Y + 25));
            }
        }

        //code for loading in map image
        private void openMapImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openMap.Title = "Select the image";
            openMap.FileName = "";
            openMap.Filter = "Images|*.jpg;*.png;*.gif;*.bmp";
            openMap.ShowDialog();
        }

        //splits the string to look for which edges are in it
        private void EdgeBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            string[] splitString = ((string)EdgeBox.SelectedItem).Split(delimiters);
        }

        //code for loading in images
        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            pictureBox1.Image = System.Drawing.Image.FromFile(openMap.FileName);
            string[] splitString = openMap.FileName.Split('\\');
            PFInfo.map.file = splitString.Last();
            PFInfo.map.height = 900;
            PFInfo.map.width = 500;
        }

        //contains code to delete an edge
        private void DelCon_Click(object sender, EventArgs e)
        {
            if (EdgeBox.SelectedItem != null)
            {
                string[] splitString = ((string)EdgeBox.SelectedItem).Split(delimiters);

                Edge Deleteable = PFInfo.nodeInfo.EdgeList
                    .Select<Edge, Edge>(Edge => Edge)
                    .Where(edge => edge.startID == uint.Parse(splitString[0]) && edge.endID == uint.Parse(splitString[3]))
                    .First();

                PFInfo.nodeInfo.EdgeList.Remove(Deleteable);
                EdgeBox.Items.Remove(EdgeBox.SelectedItem);
                foreach (Button button in buttons)
                {
                    button.Invalidate();
                }
            }
        }

        //contains code to show the save xml dialog box
        private void saveXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveXML.Title = "Create the map";
            saveXML.FileName = ".map";
            saveXML.Filter = "Map Files (*.map)|*.map";
            saveXML.ShowDialog();
        }

        //contains code to show the open xml dialog box
        private void openXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openXML.Title = "Create the map";
            openXML.FileName = "";
            openXML.Filter = "Map Files (*.map)|*.map";
            openXML.ShowDialog();
        }

        //contains code for the loading in of an xml code
        private void openFileDialog3_FileOk(object sender, CancelEventArgs e)
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(PathfindingInfo));
            TextReader reader = new StreamReader(openXML.FileName);
            var temp = (PathfindingInfo)deserializer.Deserialize(reader);
            foreach (Button b in buttons)
            {
                b.BackColor = Color.Transparent;
            }
            EdgeBeginDrop.Items.Clear();
            EdgeEndDrop.Items.Clear();
            EdgeBox.Items.Clear();
            foreach (Node n in temp.nodeInfo.NodeList)
            {
                EdgeBeginDrop.Items.Add(n.id);
                EdgeEndDrop.Items.Add(n.id);
                buttons[n.id].BackColor = Color.FromArgb(90, 255, 50, 255);
            }
            foreach (Edge d in temp.nodeInfo.EdgeList)
            {
                EdgeBox.Items.Add(d.startID + " to" + d.endID);
            }
            pictureBox1.Image = System.Drawing.Image.FromFile("../../" + temp.map.file);
            PFInfo = temp;
            reader.Close();
        }

        //contains code for the saving of xml
        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(PathfindingInfo));
            TextWriter writer = new StreamWriter(saveXML.FileName);
            serializer.Serialize(writer, PFInfo);
            writer.Close();
        }

        private void moveUp_Click(object sender, EventArgs e)
        {
            var tempIndex = EdgeBox.SelectedIndex;
            if (tempIndex - 1 > -1)
            {
                var tempItem = EdgeBox.Items[tempIndex - 1];
                EdgeBox.Items[tempIndex - 1] = EdgeBox.SelectedItem;
                EdgeBox.Items[tempIndex] = tempItem;
                EdgeBox.SelectedItem = EdgeBox.Items[tempIndex - 1];

                var tempEdge = PFInfo.nodeInfo.EdgeList[tempIndex - 1];
                PFInfo.nodeInfo.EdgeList[tempIndex - 1] = PFInfo.nodeInfo.EdgeList[tempIndex];
                PFInfo.nodeInfo.EdgeList[tempIndex] = tempEdge;
            }
                
            
        }

        private void moveDown_Click(object sender, EventArgs e)
        {
            var tempIndex = EdgeBox.SelectedIndex;
            if (tempIndex + 1 < EdgeBox.Items.Count)
            {
                var tempItem = EdgeBox.Items[tempIndex + 1];
                EdgeBox.Items[tempIndex + 1] = EdgeBox.SelectedItem;
                EdgeBox.Items[tempIndex] = tempItem;
                EdgeBox.SelectedItem = EdgeBox.Items[tempIndex + 1];

                var tempEdge = PFInfo.nodeInfo.EdgeList[tempIndex + 1];
                PFInfo.nodeInfo.EdgeList[tempIndex + 1] = PFInfo.nodeInfo.EdgeList[tempIndex];
                PFInfo.nodeInfo.EdgeList[tempIndex] = tempEdge;
            }
        }

        

        
    }
}